import time
from typing import List
from utils.logging_conf import logger
from .Nginxloginfo import NginxLogInfo
from .alert_event import AlertEvent
from utils.send_email import MailSender
from datetime import datetime,timedelta
import os


class NginxLogMonitor(NginxLogInfo):
    def __init__(self, name, log_file,alert_event_list:List[AlertEvent],to_email,EMAIL_ADDRESS,EMAIL_PASSWORD,SMTP_SERVER,SMTP_PORT=587,alert_time=300,check_interval=60):
        self.log_file = log_file # 检测日志文件
        self.alert_event_list = alert_event_list
        self.EMAIL_ADDRESS = EMAIL_ADDRESS
        self.EMAIL_PASSWORD = EMAIL_PASSWORD
        self.SMTP_SERVER = SMTP_SERVER
        self.SMTP_PORT =SMTP_PORT
        self.mailsender = MailSender(self.EMAIL_ADDRESS,self.EMAIL_PASSWORD,self.SMTP_SERVER,self.SMTP_PORT)
        self.to_email = to_email
        self.alert_time = alert_time
        self.alert_info = {}
        self.name = name
        super(NginxLogMonitor, self).__init__(check_interval)

    def handle_event(self):
        ip_info = self.get_ip_info()
        status_info = self.get_status_info()
        logger.info(f"ip服务情况：{ip_info}")
        logger.info(f"事件访问情况：{status_info}")

        for event in self.alert_event_list:
            if event.alert(status_info,ip_info,self.log_info):
                now_time = datetime.now()
                # 获取该事件上次报警时间，默认为当前时间减去报警间隔（确保首次能触发）
                last_alert_time = self.alert_info.get(event.event_name, now_time - timedelta(seconds=self.alert_time))
                # 计算距离上次报警的时间差（秒）
                time_diff = (now_time - last_alert_time).total_seconds()
                # 当时间差大于等于报警间隔时，发送报警邮件
                if time_diff >= self.alert_time:
                    logger.info(f"触发警告事件：{event.event_name}")

                    # 发送邮件
                    end_content = f"""
                   
监听器名称：{self.name}
警告事件：{event.event_name}
警告时间：{now_time.strftime('%Y-%m-%d %H:%M:%S')}
                    """
                    # 发送邮箱
                    self.mailsender.send_email(self.to_email,event.event_name,event.event_content+end_content)

                    self.alert_info[event.event_name] = now_time

    def monitor_nginx_log(self):
        logger.info(f"开始监控日志文件：{self.log_file}")
        logger.info(f"检查间隔：{self.check_interval}s")
        last_file_size = 0
        last_inode = None
        f = None  # 初始化文件句柄

        try:
            while True:
                # 检查文件是否存在
                if not os.path.exists(self.log_file):
                    logger.error(f"日志文件 {self.log_file} 不存在，将在 {self.check_interval}s 后重试")
                    time.sleep(self.check_interval)
                    continue

                # 获取当前文件的inode
                current_stat = os.stat(self.log_file)
                current_inode = current_stat.st_ino

                # 如果inode变化（文件被替换）或文件句柄未初始化，重新打开文件
                if f is None or current_inode != last_inode:
                    if f is not None:
                        f.close()  # 关闭旧文件句柄
                    logger.info(f"打开/重新打开日志文件：{self.log_file}")
                    f = open(self.log_file, "r")
                    f.seek(0, os.SEEK_END)  # 定位到文件末尾
                    last_inode = current_inode
                    last_file_size = current_stat.st_size  # 重置文件大小记录

                # 检查文件是否被截断（而非替换）
                current_file_size = os.fstat(f.fileno()).st_size
                if current_file_size < last_file_size:
                    logger.info("检测到日志文件被清空，重新定位到文件开头")
                    f.seek(0, os.SEEK_SET)
                    last_file_size = 0  # 重置大小记录

                # 读取新内容
                line = f.readline()
                if line:
                    log_data = self.parse_nginx_log(line)
                    if log_data:
                        self.append(log_data)
                    self.handle_event()
                    last_file_size = current_file_size  # 更新大小
                else:
                    # 没有新内容时休眠
                    time.sleep(1)
                    # 重新获取文件状态（避免长时间休眠后状态变化）
                    last_file_size = os.fstat(f.fileno()).st_size

        except KeyboardInterrupt:
            logger.error("\n监控已停止")
        except Exception as e:
            logger.error(f"监控过程中发生错误: {e}")
            raise e
        finally:
            if f is not None:
                f.close()  # 确保文件句柄关闭






